using System;
using System.Collections;

namespace Common
{
	public enum Direction{North, East, South, West};

	public abstract class MapSite : ICloneable
	{
		public abstract void Enter();

		#region ICloneable Members

		public object Clone()
		{
			return this.MemberwiseClone();
		}

		#endregion
	}
	
	public class Room : MapSite
	{
		private MapSite[] sides = new MapSite[4];

		protected int m_n;
		public int N
		{
			get{return m_n;}
		}

		public Room()
		{
			Console.WriteLine("Constructor of Room");
		}

		public Room(int n)
		{
			Console.WriteLine("Constructor of Room number {0}", n);
			m_n = n;
		}

		public virtual void Initialize(int n)
		{
			Console.WriteLine("Initializing instance of Room number {0}", n);
			m_n = n;
		}

		public void SetSide(Direction d, MapSite mapSite)
		{
			Console.WriteLine("Setting side {0} a {1}", d.ToString(), mapSite.GetType().ToString());			
			sides[(int)d] = mapSite;
		}

		public MapSite GetSide(Direction d)
		{
			return sides[(int)d];
		}

		public override void Enter()
		{

		}

		#region ICloneable Members

		public new object Clone()
		{
			Console.WriteLine("Cloning Room");
			return this.MemberwiseClone();
		}

		#endregion
	}

	public class Wall : MapSite
	{
		public Wall()
		{
			Console.WriteLine("Constructor of Wall");
		}
		
		public override void Enter(){}
		#region ICloneable Members

		public new object Clone()
		{
			Console.WriteLine("Cloning Wall");
			return this.MemberwiseClone();
		}

		#endregion
	}

	public class Door : MapSite
	{
		protected Room m_r1;
		protected Room m_r2;
		protected bool isOpen;

		public Room R1
		{
			get{return m_r1;}
		}

		public Room R2
		{
			get{return m_r2;}
		}

		public Door()
		{
			Console.WriteLine("Constructor of Door");
		}

		public Door(Room r1, Room r2)
		{
			Console.WriteLine("Constructor of a door between rooms {0} and {1}.", r1.N, r2.N);
			m_r1 = r1;
			m_r2 = r2;
		}
		public virtual void Initialize(Room r1, Room r2)
		{
			Console.WriteLine("Initializing instance of a door between rooms {0} and {1}.", r1.N, r2.N);
			m_r1 = r1;
			m_r2 = r2;
		}

		public override string ToString()
		{
			return "Door between rooms: " + R1.N + ", " + R2.N;
		}

		public override void Enter()
		{

		}


		public virtual Room OtherSideFrom(Room room){ return null; }

		#region ICloneable Members

		public new object Clone()
		{
			Console.WriteLine("Cloning Door");
			return this.MemberwiseClone();
		}

		#endregion
	}

	public class Maze : ICloneable
	{
		private ArrayList rooms = new ArrayList();

		public void AddRoom(Room room)
		{
			rooms.Add(room);
		}

		public Room RoomNo(int n)
		{
			Room result = null;
			foreach(Room room in rooms)
			{
				if(room.N == n)
				{
					result = room;
					break;
				}
			}
			return result;
		}
		#region ICloneable Members

		public object Clone()
		{
			Console.WriteLine("Cloning Maze");
			return this.MemberwiseClone();
		}

		#endregion
	}

	

	/* *******************************************************
	 *					'Bombed'
	 * *******************************************************/
	public class BombedWall : Wall
	{
		public BombedWall()
		{
			Console.WriteLine("Constructor of a BombedWall");
		}
	}

	public class RoomWithABomb : Room
	{
		public RoomWithABomb()
		{
			Console.WriteLine("Constructor of RoomWithABoomb");
		}
		public RoomWithABomb(int n):base(n)
		{
			Console.WriteLine("Constructor of Room with a Bomb number {0}", n);
		}

	}

	/* *******************************************************
	 *					'Enchanted'
	 * *******************************************************/
	public class EnchantedRoom : Room
	{
		private Spell m_spell;

		public EnchantedRoom(int n, Spell spell):base(n)
		{
			Console.WriteLine("Constructor of an Enchanted Room");
			m_spell = spell;
		}
	}

	public class DoorNeedingSpell : Door
	{
		public DoorNeedingSpell(Room r1, Room r2):base(r1, r2)
		{
			Console.WriteLine("Constructor of a door needing spell bw rooms {0} and {1}",
				r1.N, r2.N);			
		}
		
		public override string ToString()
		{
			return "Enchanted door between rooms: " + R1.N + ", " + R2.N;
		}


	}

	public class Spell
	{
		public Spell()
		{
			Console.WriteLine("Constructor of Spell");
		}
	}
}
